﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;

namespace UMLDraw
{
    //объявление класса элемент Комментарий
    public class Comment
    {
        public string Name;
        public string Text;
        public int XCoor;
        public int YCoor;
        public TreeNode Node;
        public List<String> InputName = new List<String>();
        public List<String> OutputName = new List<String>();

        public PictureBox Image = new PictureBox();
        public TextBox Names = new TextBox();
        public Point[] PerimeterPoint = new Point[4];
        public PictureBox[] Marks = new PictureBox[4];
        public ToolTip Hint = new ToolTip();

        public Point Zero = Point.Empty;
        public Point Drag = Point.Empty;
        public Point Drop = Point.Empty;

        public double Scale;
        public bool isSelected;

        public Comment()
        {
            Name = "Comment";
            Text = "Комментарий";
            XCoor = 0;
            YCoor = 0;
            Node = new TreeNode("Comment");
            Node.Name = "Comment";
            Node.Text = "Комментарий";
            Scale = 1;
            isSelected = false;
        }

        public void Initialize(string name, string text, Panel panel, int x, int y)
        {
            // textBox
            Name = name;
            Text = text;
            XCoor = x;
            YCoor = y;
            Node.Name = name;
            Node.Text = text;
            this.Image.Controls.Add(Names);
            Names.Name = name;
            Names.Text = text;
            Names.Multiline = true;
            Names.Size = new System.Drawing.Size(110, 56);
            Names.Location = new System.Drawing.Point(x + 6, y + 6);
            Names.BorderStyle = BorderStyle.None;
            Names.TabIndex = 5 + Convert.ToInt16(name.Replace("Comment", ""))*100;
            Names.BringToFront();
            this.Names.Leave += new System.EventHandler(this.Name_Changed);
            this.Names.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Name_MouseDown);
            panel.Controls.Add(Names);

            //pictureBox
            Image.Location = new System.Drawing.Point(x, y);
            Image.Name = name;
            Image.BackgroundImageLayout = ImageLayout.Zoom;
            Image.Cursor = System.Windows.Forms.Cursors.Hand;
            Image.Size = new Size(130, 70);
            Image.BackgroundImage = global::UMLDraw.Properties.Resources.Comment;
            Image.TabIndex = 0;
            Image.BringToFront();
            this.Image.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Image_MouseMove);
            this.Image.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Image_MouseDown);
            this.Image.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.Image_PreviewKeyDown);
            this.Image.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Image_MouseUp);
            this.Image.GotFocus += new EventHandler(Image_GotFocus);
            this.Image.LostFocus += new EventHandler(Image_LostFocus);
            panel.Controls.Add(Image);
            //perimetrPoint
            setPerimeterPoints(x, y);

            for (int i = 0; i < 4; i++)
            {
                Image.Controls.Add(Marks[i]);
                Marks[i] = new PictureBox();
                Marks[i].Location = PerimeterPoint[i];
                Marks[i].Size = new Size(2, 2);
                Marks[i].BackColor = Color.Blue;
                Marks[i].Hide();
                Marks[i].TabIndex = 0;
                Marks[i].BringToFront();
                panel.Controls.Add(Marks[i]);
                panel.Refresh();
            }
            Hint.ToolTipTitle = "Комментарий";
            Hint.SetToolTip(Names, Names.Text);

        }
        public void setPerimeterPoints(int X, int Y)
        {
            PerimeterPoint[0] = new Point(X - 1 + Image.Width / 2, Y - 2);
            PerimeterPoint[1] = new Point(X - 2, Y + Image.Height / 2);
            PerimeterPoint[2] = new Point(X + Image.Width, Y + Image.Height / 2);
            PerimeterPoint[3] = new Point(X - 1 + Image.Width / 2, Y + Image.Height);
        }
        private void Name_MouseDown(object sender, MouseEventArgs e)
        {
            UMLDraw.MainForm.WPlace.selectSth(Name);
        }
        private void Name_Changed(object sender, EventArgs e)
        {
            Control c = sender as Control;
            if (Text != c.Text)
            {
                Text = c.Text;
                UMLDraw.MainForm.WPlace.tree.Nodes[c.Name].Text = c.Text;
                Hint.SetToolTip(Names, Names.Text);
                MainForm link = new MainForm();
                link.NewHistoryRec();
            }
        }

        private void Image_MouseDown(object sender, MouseEventArgs e)
        {
            Control c = sender as Control;
            Zero = c.Location;

            Drag.X = Cursor.Position.X;
            Drag.Y = Cursor.Position.Y;
            c.Focus();
        }

        private void Image_MouseMove(object sender, MouseEventArgs e)
        {
            Control c = sender as Control;
            if (e.Button == MouseButtons.Left)
            {
                Drop.X = Zero.X + Cursor.Position.X - Drag.X;
                Drop.Y = Zero.Y + Cursor.Position.Y - Drag.Y;
                c.Location = Drop;
                this.Names.Location = new System.Drawing.Point(Drop.X + Convert.ToInt16(6 * Scale), Drop.Y + Convert.ToInt16(6 * Scale));

                setPerimeterPoints(Drop.X, Drop.Y);
                for (int i = 0; i < 4; i++)
                    Marks[i].Location = PerimeterPoint[i];
                Image.Refresh();
                Names.Refresh();
            }
        }

        private void Image_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            Control c = sender as Control;
            if (e.KeyValue == 46)
            {
                c.Dispose();
                this.Names.Dispose();
                for (int i = 0; i < 4; i++)
                    this.Marks[i].Dispose();
                UMLDraw.MainForm.WPlace.tree.Nodes[c.Name].Remove();

                for (int i = 0; i < this.InputName.Count(); i++)
                    try
                    {
                        UMLDraw.MainForm.WPlace.tree.Nodes[this.InputName[i]].Remove();
                        UMLDraw.MainForm.TFer[findList(this.InputName[i])].Line.Dispose();
                        UMLDraw.MainForm.TFer[findList(this.InputName[i])].Names.Dispose();
                    }
                    catch { }
                for (int i = 0; i < this.OutputName.Count(); i++)
                    try
                    {
                        UMLDraw.MainForm.WPlace.tree.Nodes[this.OutputName[i]].Remove();
                        UMLDraw.MainForm.TFer[findList(this.OutputName[i])].Line.Dispose();
                        UMLDraw.MainForm.TFer[findList(this.OutputName[i])].Names.Dispose();
                    }
                    catch { }
            }
        }
        private int findList(string key)
        {
            int result = -1;
            for (int i = 0; i < UMLDraw.MainForm.TFer.Count(); i++)
                if (UMLDraw.MainForm.TFer[i].Line.Name == key)
                    result = i;
            return result;
        }
        private void Image_MouseUp(object sender, MouseEventArgs e)
        {
            Control c = sender as Control;
            if (UMLDraw.MainForm.WPlace.CurrentAction == "AddTransfer")      //если добавляется новый элемент
            {
                AppendTransfer(c);
            }
            if (UMLDraw.MainForm.WPlace.CurrentAction == "SelectItem")       //если перемещается существующий элемент
            {
                if (UMLDraw.MainForm.TFer.Count() > 0)
                {
                    RewriteTransfer(c);
                }
                if (XCoor != Image.Location.X || YCoor != Image.Location.Y)
                {
                    XCoor = Image.Location.X;
                    YCoor = Image.Location.Y;
                    UMLDraw.MainForm.WPlace.refreshAll();
                    MainForm link = new MainForm();
                    link.NewHistoryRec();
                }
            }
        }

        private void AppendTransfer(Control c)
        {
            int nP;
            if (UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].FromName == "Unknown")
            {
                nP = NearestPoint(UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.X2, UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Y2);
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.X1 = this.PerimeterPoint[nP].X;
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Y1 = this.PerimeterPoint[nP].Y;
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.BorderStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Names.Hide();
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].FromName = c.Name;
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].LNames.Hide();
                UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Node.Text = "Связь с комментарием";
                this.OutputName.Add(UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Name);
            }
            else
                if (UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].ToName == "Unknown")
                {
                    if (UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].FromName != c.Name)
                    {
                        nP = NearestPoint(UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.X1, UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Y1);
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.X2 = this.PerimeterPoint[nP].X;
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Y2 = this.PerimeterPoint[nP].Y;
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.BorderStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Names.Hide();
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].ToName = c.Name;
                        this.InputName.Add(UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Name);

                        //получив две точки, отрисовываем линию
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Line.Show();
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].LNames.Hide();
                        UMLDraw.MainForm.TFer[UMLDraw.MainForm.TFer.Count() - 1].Node.Text = "Связь с комментарием";
                        UMLDraw.MainForm.WPlace.CurrentAction = "SelectItem";
                    }
                    else
                    {
                        MessageBox.Show("Нельзя создать петлю");
                    }
                }
        }
        public void RewriteTransfer(Control c)
        {
            for (int i = 0; i < UMLDraw.MainForm.TFer.Count; i++)
                if (UMLDraw.MainForm.TFer[i].FromName == c.Name)
                {
                    UMLDraw.MainForm.TFer[i].Line.X1 = this.PerimeterPoint[NearestPoint(UMLDraw.MainForm.TFer[i].Line.X2, UMLDraw.MainForm.TFer[i].Line.Y2)].X;
                    UMLDraw.MainForm.TFer[i].Line.Y1 = this.PerimeterPoint[NearestPoint(UMLDraw.MainForm.TFer[i].Line.X2, UMLDraw.MainForm.TFer[i].Line.Y2)].Y;
                    try
                    {
                        UMLDraw.MainForm.TFer[i].Line.BorderStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                        UMLDraw.MainForm.TFer[i].Names.Hide();
                    }
                    catch { }
                }
                else
                    if (UMLDraw.MainForm.TFer[i].ToName == c.Name)
                    {
                        UMLDraw.MainForm.TFer[i].Line.X2 = this.PerimeterPoint[NearestPoint(UMLDraw.MainForm.TFer[i].Line.X1, UMLDraw.MainForm.TFer[i].Line.Y1)].X;
                        UMLDraw.MainForm.TFer[i].Line.Y2 = this.PerimeterPoint[NearestPoint(UMLDraw.MainForm.TFer[i].Line.X1, UMLDraw.MainForm.TFer[i].Line.Y1)].Y;
                        try
                        {
                            UMLDraw.MainForm.TFer[i].Line.BorderStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                            UMLDraw.MainForm.TFer[i].Names.Hide();
                        }
                        catch { }

                        //получив две точки, отрисовываем линию
                        UMLDraw.MainForm.TFer[i].Line.Show();
                        UMLDraw.MainForm.WPlace.CurrentAction = "SelectItem";
                    }
        }

        private void Image_GotFocus(object sender, EventArgs e)
        {
            //isSelected = true;
            //for (int i = 0; i < 4; i++)
            //    this.Marks[i].Show();
            UMLDraw.MainForm.WPlace.selectSth(Name);
        }

        private void Image_LostFocus(object sender, EventArgs e)
        {
            //for (int i = 0; i < 4; i++)
            //    this.Marks[i].Hide();
            //UMLDraw.MainForm.WPlace.selectSth("WP");
        }

        private int NearestPoint(int X, int Y)
        {
            double min = System.Math.Sqrt(System.Math.Pow(System.Math.Abs(X - PerimeterPoint[0].X), 2) + System.Math.Pow(System.Math.Abs(Y - PerimeterPoint[0].Y), 2));
            int minIndex = 0;

            for (int i = 1; i < 4; i++)
            {
                double range = System.Math.Sqrt(System.Math.Pow(System.Math.Abs(X - PerimeterPoint[i].X), 2) + System.Math.Pow(System.Math.Abs(Y - PerimeterPoint[i].Y), 2));
                if (range < min)
                {
                    min = range;
                    minIndex = i;
                }
            }
            return minIndex;
        }
    }

}
